#include <webx/route.h>
#include <dbentity/T_XG_ROUTE.h>

class ExportRoute : public webx::ProcessBase
{
protected:
	int process();
	bool checkClient();
};

HTTP_WEBAPP(ExportRoute)

class RouteItem
{
public:
	int port;
	int weight;
	string host;
};

int ExportRoute::process()
{
	int res = 0;
	int num = 0;
	int type = CGI_PUBLIC;

	checkClient();

	param_string(format);
	param_string(access);

	if (IsNumberString(access.c_str()))
	{
		type = stdx::atoi(access.c_str());
	}
	else
	{
		stdx::tolower(access);

		if (access == "disable") type = CGI_DISABLE;
		else if (access == "private") type = CGI_PRIVATE;
		else if (access == "protect") type = CGI_PROTECT;
	}

	if (stdx::toupper(format) != "NGINX") format = "JSON";

	string data;
	string etag;
	string version = request->getHeadValue("If-None-Match");
	sp<Session> session = webx::GetLocaleSession("SYSTEM_ROUTELIST", 10);

	if (!session) return simpleResponse(XG_SYSERR);

	string key = stdx::format("{%s:%d}", format.c_str(), type);
	string vkey = stdx::format("{%s:%d:V}", format.c_str(), type);

	if (session->get(key, data))
	{
		etag = session->get(vkey);
	}
	else
	{
		CT_XG_ROUTE tab;
		map<string, vector<RouteItem>> routemap;

		tab.init(webx::GetDBConnect());

		if (tab.find("ENABLED>0 AND PROCTIME>0 ORDER BY ID ASC"))
		{
			while (tab.next())
			{
				JsonElement json(tab.content.toString());

				if (json["list"].isArray())
				{
					JsonElement vec = json["list"];

					for (auto item : vec)
					{
						string url = item["path"].asString();
						int enabled = item["enabled"].asInt();

						if (enabled > 0 && type <= enabled)
						{
							RouteItem route;

							route.port = tab.port.val();
							route.host = tab.host.val();
							route.weight = tab.enabled.val();

							routemap[url].push_back(route);
						}
					}

					num++;
				}
			}
		}

		tab.close();

		if (format == "NGINX")
		{
			string upstream;
			string location;

			for (auto& item : routemap)
			{
				++res;

				string server;

				for (auto& route : item.second) stdx::append(server, "\tserver %s:%d weight=%d;\n", route.host.c_str(), route.port, route.weight);

				stdx::append(location, "location ~* /%s {\n\tproxy_pass http://%03d;\n}\n", item.first.c_str(), res);

				stdx::append(upstream, "upstream %03d{\n%s}\n", res, server.c_str());
			}

			json["upstream"] = upstream;
			json["location"] = location;
		}
		else
		{
			JsonElement arr = json.addArray("list");

			for (auto& item : routemap)
			{
				int idx = 0;
				JsonElement data = arr[res++];

				data["path"] = item.first;

				for (auto& route : item.second)
				{
					JsonElement host = data["list"][idx++];

					host["host"] = route.host;
					host["port"] = route.port;
					host["weight"] = route.weight;
				}
			}

			HostItem loghost = webx::GetLogHost();
			JsonElement logconf = json.addObject("log");

			if (loghost.canUse())
			{
				logconf["host"] = loghost.host;
				logconf["port"] = loghost.port;
			}
			else
			{
				logconf["host"] = app->getHost();
				logconf["port"] = app->getPort();
			}

			if (RedisConnect::CanUse())
			{
				sp<RedisConnect> redis = RedisConnect::Instance();

				if (redis)
				{
					JsonElement redisconf = json.addObject("redis");

					redisconf["password"] = redis->getPassword();
					redisconf["host"] = redis->getHost();
					redisconf["port"] = redis->getPort();
				}
			}
		}

		data = json.toString();
		etag = MD5GetEncodeString(data.c_str(), data.length(), true).val;

		json["code"] = res;

		data = json.toString();
		session->set(key, data);
		session->set(vkey, etag);
	}

	if (etag == version) throw Exception(XG_NOTCHANGED);

	response->setHeadValue("ETag", etag);

	out << data;

	return XG_OK;
}

bool ExportRoute::checkClient()
{
	param_int(clientid);
	param_int(clientport);
	param_string(clienthost);
	param_string(clientname);

	CHECK_FALSE_RETURN(clientid > 0 && clientport > 0 && clientname.length() > 0);

	if (clienthost.empty() || clienthost == LOCAL_IP)
	{
		clienthost = response->getSocket()->getAddress().host;

		CHECK_FALSE_RETURN(clienthost.length() > 0);
	}

	CT_XG_ROUTE tab;

	tab.init(webx::GetDBConnect());

	tab.findWhere("NAME=? AND HOST=? AND PORT=?", clientname, clienthost, clientport);

	CHECK_FALSE_RETURN(tab.getErrorCode() == 0);

	if (tab.next()) return true;

	CHECK_FALSE_RETURN(tab.getErrorCode() == 0);

	tab.enabled = 1;
	tab.name = clientname;
	tab.host = clienthost;
	tab.port = clientport;
	tab.statetime.update();

	for (int i = 0; i < 5; i++)
	{
		tab.id = DateTime::GetBizId();

		if (tab.insert() >= 0) return true;
	}

	return false;
}